import { BaseResponse } from '@/common/BaseResponse';
import { DictionaryWords } from '@/entity/dictionary-words.entity';
import { Dictionary } from '@/entity/dictionary.entity';
import { getExcelData } from '@/utils/file';
import { HttpException, Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { PageParamDto } from './dto/page-param.dto';
import { DictionaryWordsDto } from './dto/dictionary-words.dto';
import { DictionaryDto } from './dto/dictionary.dto';
import { DictionaryStudyRecord } from '@/entity/dictionary-study-record.entity';
import { AnswerProblemDto } from './dto/answer-problem.dto';
import { HTTP_CUSTOM_CODE } from '@/enum/http-custom-code';
import { DictionaryStudyRecordError } from '@/entity/dictionary-study-record-error.entity';
import { CollectionWordDto } from './dto/collectionw-word.dto';
import { DictionaryCollection } from '@/entity/dictionary-collection.entity';
import { DOUBLE_STATUS } from '@/enum/common';
import { RandDataDto } from './dto/rand-data.dto';

@Injectable()
export class DictionaryService {
  constructor(
    @InjectRepository(Dictionary)
    private readonly dictionaryRepository: Repository<Dictionary>,
    @InjectRepository(DictionaryWords)
    private readonly dictionaryWordsRepository: Repository<DictionaryWords>,
    @InjectRepository(DictionaryStudyRecord)
    private readonly dictionaryStudyRecordRepository: Repository<DictionaryStudyRecord>,
    @InjectRepository(DictionaryStudyRecordError)
    private readonly dictionaryStudyRecordErrorRepository: Repository<DictionaryStudyRecordError>,
    @InjectRepository(DictionaryCollection)
    private readonly dictionaryCollectionRepository: Repository<DictionaryCollection>,
  ) {}

  getDictionaryList() {
    return this.dictionaryRepository.find();
  }

  async addDictionary(dictionaryDto: DictionaryDto) {
    // 判断是否名称已存在
    const result = await this.dictionaryRepository.findOne({
      where: {
        dictionaryName: dictionaryDto.dictionaryName,
      },
    });
    if (result) {
      throw new HttpException('该词典已存在', 500);
    }
    const dictionary = new Dictionary();
    dictionary.dictionaryName = dictionaryDto.dictionaryName;
    return this.dictionaryRepository.save(dictionary);
  }

  async addDictionaryWords(dictionaryWordsDto: DictionaryWordsDto) {
    console.log(dictionaryWordsDto);
    const list = await getExcelData(dictionaryWordsDto.dictionaryExcelPath);
    console.log(list.length);

    for (let i = 0; i < list.length; i++) {
      const wordItem = list[i];
      const word = new DictionaryWords();
      word.dictionaryId = dictionaryWordsDto.dictionaryId;
      word.wordContent = wordItem.wordContent;
      word.wordTranslate = wordItem.wordTranslate;
      word.wordPronunciation = wordItem.wordPronunciation;
      await this.dictionaryWordsRepository.save(word);
    }
    return BaseResponse.toSuccesJustMsg('添加词汇成功！');
  }

  async getDictionaryWords(pageParamDto: PageParamDto, userId: number) {
    const qb =
      this.dictionaryWordsRepository.createQueryBuilder('dictionaryWords');
    const result = qb.andWhere(
      'dictionaryWords.dictionary_id = :dictionaryId',
      {
        dictionaryId: pageParamDto.dictionaryId,
      },
    );
    if (userId) {
      const studyRecord = await this.dictionaryStudyRecordRepository.find({
        select: {
          id: true,
        },
        where: {
          userId: userId,
          dictionaryId: pageParamDto.dictionaryId,
        },
      });
      console.log('studyRecord', studyRecord);
    }
    result
      .andWhere(
        `(select count(1) as num from dictionary_study_record where dictionary_study_record.word_id = dictionaryWords.id and dictionary_study_record.dictionary_id = :dictionaryId and dictionary_study_record.user_id = :userId) = 0`,
        {
          dictionaryId: pageParamDto.dictionaryId,
          userId: userId,
        },
      )
      .limit(pageParamDto.size)
      .offset((pageParamDto.current - 1) * pageParamDto.size);
    const total = await result.getCount();
    const list = await result.getMany();

    for (let i = 0; i < list.length; i++) {
      const dictionaryWords = list[i];
      const collectionResult =
        await this.dictionaryCollectionRepository.findOne({
          where: {
            wordId: dictionaryWords.id,
            userId: userId,
            dictionaryId: dictionaryWords.dictionaryId,
          },
        });
      if (collectionResult) {
        list[i].collectionStatus = collectionResult.status;
      } else {
        list[i].collectionStatus = DOUBLE_STATUS.UN_NORMAL;
      }
    }

    return BaseResponse.toSuccesJustData({
      current: Number(pageParamDto.current),
      list,
      size: Number(pageParamDto.size),
      total,
    });
  }

  async answerOneProblem(answerProblemDto: AnswerProblemDto) {
    // 判断答案是否正确
    const realAnswer = await this.dictionaryWordsRepository.findOne({
      where: {
        dictionaryId: answerProblemDto.dictionaryId,
        id: answerProblemDto.wordId,
      },
    });
    if (!realAnswer) {
      throw new HttpException('单词不存在', 400);
    }
    if (realAnswer.wordTranslate.includes(answerProblemDto.answer)) {
      // 判断是否已经答题
      const studyRecordResult =
        await this.dictionaryStudyRecordRepository.findOne({
          where: {
            dictionaryId: answerProblemDto.dictionaryId,
            wordId: answerProblemDto.wordId,
          },
        });

      if (!studyRecordResult) {
        const studyRecord = new DictionaryStudyRecord();
        studyRecord.dictionaryId = answerProblemDto.dictionaryId;
        studyRecord.wordId = answerProblemDto.wordId;
        studyRecord.userId = answerProblemDto.userId;
        await this.dictionaryStudyRecordRepository.save(studyRecord);
      }

      return BaseResponse.toSuccesJustMsg('回答正确');
    }
    const realAnswerError =
      await this.dictionaryStudyRecordErrorRepository.findOne({
        where: {
          dictionaryId: answerProblemDto.dictionaryId,
          wordId: answerProblemDto.wordId,
          userId: answerProblemDto.userId,
        },
      });
    if (!realAnswerError) {
      const studyRecordError = new DictionaryStudyRecordError();
      studyRecordError.answerError = answerProblemDto.answer;
      studyRecordError.answer = realAnswer.wordTranslate;
      studyRecordError.dictionaryId = answerProblemDto.dictionaryId;
      studyRecordError.userId = answerProblemDto.userId;
      studyRecordError.wordId = answerProblemDto.wordId;
      await this.dictionaryStudyRecordErrorRepository.save(studyRecordError);
    } else {
      realAnswerError.answerError = answerProblemDto.answer;
      await this.dictionaryStudyRecordErrorRepository.update(
        realAnswerError.id,
        realAnswerError,
      );
    }
    return BaseResponse.toError(HTTP_CUSTOM_CODE.ANSWER_ERROR, '回答错误');
  }

  async answerMannyProblem(answerProblemDtoList: AnswerProblemDto[]) {
    for (let i = 0; i < answerProblemDtoList.length; i++) {
      const answerProblemDto = answerProblemDtoList[i];
      // 判断是否已经答题
      const studyRecordResult =
        await this.dictionaryStudyRecordRepository.findOne({
          where: {
            dictionaryId: answerProblemDto.dictionaryId,
            wordId: answerProblemDto.wordId,
          },
        });

      if (!studyRecordResult) {
        const studyRecord = new DictionaryStudyRecord();
        studyRecord.dictionaryId = answerProblemDto.dictionaryId;
        studyRecord.wordId = answerProblemDto.wordId;
        studyRecord.userId = answerProblemDto.userId;
        await this.dictionaryStudyRecordRepository.save(studyRecord);
      }
    }
    return BaseResponse.toSuccesJustMsg('批量答题成功！');
  }

  async collectionWord(collectionWordDto: CollectionWordDto) {
    // 判断是否已收藏
    const collectionResult = await this.dictionaryCollectionRepository.findOne({
      where: {
        wordId: collectionWordDto.wordId,
        userId: collectionWordDto.userId,
        dictionaryId: collectionWordDto.dictionaryId,
      },
    });
    if (collectionResult) {
      collectionResult.status =
        collectionResult.status === DOUBLE_STATUS.NORMAL
          ? DOUBLE_STATUS.UN_NORMAL
          : DOUBLE_STATUS.NORMAL;
      await this.dictionaryCollectionRepository.update(
        collectionResult.id,
        collectionResult,
      );
      return BaseResponse.toSuccesJustData(collectionResult);
    }
    const collectionRecord = new DictionaryCollection();
    collectionRecord.dictionaryId = collectionWordDto.dictionaryId;
    collectionRecord.userId = collectionWordDto.userId;
    collectionRecord.wordId = collectionWordDto.wordId;
    const result = await this.dictionaryCollectionRepository.save(
      collectionRecord,
    );
    return BaseResponse.toSuccesJustData(result);
  }

  getRanDataLimit(randData: RandDataDto) {
    const qb =
      this.dictionaryWordsRepository.createQueryBuilder('dictionaryWords');
    const result = qb
      .andWhere('dictionaryWords.id != :id', {
        id: randData.id,
      })
      .addOrderBy('rand()')
      .limit(randData.limit);
    return result.getMany();
  }

  async getMyCollectionWords(userId: number) {
    const result = this.dictionaryCollectionRepository.createQueryBuilder(
      'dictionaryCollection',
    );
    const list = await result
      .addOrderBy('dictionaryCollection.create_time', 'DESC')
      .andWhere('dictionaryCollection.user_id = :userId', {
        userId,
      })
      .leftJoinAndMapOne(
        'dictionaryCollection.wordInfo',
        DictionaryWords,
        'dictionaryWords',
        'dictionaryWords.id = dictionaryCollection.word_id',
      )
      .getMany();
    return list;
  }

  async getMyStudyWordsHistory(userId: number) {
    const result = this.dictionaryStudyRecordRepository.createQueryBuilder(
      'dictionaryStudyRecord',
    );
    const list = await result
      .addOrderBy('dictionaryStudyRecord.create_time', 'DESC')
      .andWhere('dictionaryStudyRecord.user_id = :userId', {
        userId,
      })
      .leftJoinAndMapOne(
        'dictionaryStudyRecord.wordInfo',
        DictionaryWords,
        'dictionaryWords',
        'dictionaryWords.id = dictionaryStudyRecord.word_id',
      )
      .getMany();
    return list;
  }

  async getMyErrorWords(userId: number) {
    const result = this.dictionaryStudyRecordErrorRepository.createQueryBuilder(
      'dictionaryStudyRecordError',
    );
    const list = await result
      .addOrderBy('dictionaryStudyRecordError.create_time', 'DESC')
      .andWhere('dictionaryStudyRecordError.user_id = :userId', {
        userId,
      })
      .leftJoinAndMapOne(
        'dictionaryStudyRecordError.wordInfo',
        DictionaryWords,
        'dictionaryWords',
        'dictionaryWords.id = dictionaryStudyRecordError.word_id',
      )
      .getMany();
    return list;
  }

  getDetail(id: number) {
    return this.dictionaryWordsRepository
      .createQueryBuilder('dictionaryWords')
      .andWhere('id = :id', {
        id,
      })
      .limit(1)
      .getOne();
  }
}
